#include "TSS_Queue.h"

//从指定地址偏移一定的长度，进行数据读写
#define MEM_MOVE_8(p, size) *((volatile uint8_t *)p + (size))
#define MEM_MOVE_16(p, size) *((volatile uint16_t *)p + (size) / 2)
#define MEM_MOVE_32(p, size) *((volatile uint32_t *)p + (size) / 4)
//偏移的重要地址
#define MEM_SIZE() MEM_MOVE_16(queue, 0)                                     //内存大小
#define MEM_NUM() MEM_MOVE_16(queue, 2)                                      //数据个数
#define MEM_OCC() MEM_MOVE_16(queue, 4)                                      //当前数据占用的长度
#define MEM_LEN(n) MEM_MOVE_16(queue, MEM_SIZE() - 2 * n)                    //第n个数据的宽度
#define MEM_DATAF() (&MEM_MOVE_8(queue, 6))                                  //frist数据的地址
#define MEM_DATAE() (&MEM_MOVE_8(queue, 6 + MEM_OCC() - MEM_LEN(MEM_NUM()))) //end数据的地址
#define MEM_SPACE() (int32_t)(MEM_SIZE() - 6 - MEM_NUM() * 2 - MEM_OCC())    //剩余内存空间

/**
  * @brief  TSS队列初始化
  * @param  queue  管理内存的首地址
  * @param  size   内存的大小,最大支持到65535
  * @retval 返回成功或者失败
  * @note   需提供给队列一块全局内存空间
  *         本模块会在给定的内存空间内操作数据
  */
int8_t TSS_QueueInit(void *queue, uint16_t size)
{
    if (size < 8)
        return TSS_MEMSIZE;
    memset(queue, 0, size);
    MEM_SIZE() = size;
    return TSS_OK;
}

/**
  * @brief  将一块内存推入TSS队列
  * @param  queue  管理内存的首地址
  * @param  data   要推入数据的首地址
  * @param  len    要推入数据的内存大小
  * @retval 返回成功或者失败
  * @note   无
  */
int8_t TSS_QueuePush(void *queue, void *data, uint16_t len)
{
    if (MEM_SPACE() < len + 2)
        return TSS_MEMFULL;
    memcpy((void *)(MEM_DATAE() + MEM_LEN(MEM_NUM())), data, len);
    MEM_NUM() += 1;
    MEM_OCC() += len;
    MEM_LEN(MEM_NUM()) = len;
    return TSS_OK;
}

/**
  * @brief  返回数据个数
  * @param  queue  管理内存的首地址
  * @retval 返回数据个数
  * @note   无
  */
uint16_t TSS_QueueSize(void *queue)
{
    return MEM_NUM();
}

/**
  * @brief  输出第一个数据
  * @param  queue  管理内存的首地址
  * @param  data   要输出数据的首地址
  * @param  len    要输出数据的内存大小
  * @retval 返回成功或者失败
  * @note   并不会顶出数据
  */
int8_t TSS_QueueFront(void *queue, void *data, uint16_t *len)
{
    if (MEM_NUM() == 0)
        return TSS_NODATA;
    memcpy((void *)data, (void *)MEM_DATAF(), MEM_LEN(1));
    *len = MEM_LEN(1);
    return TSS_OK;
}

/**
  * @brief  输出最后一个数据
  * @param  queue  管理内存的首地址
  * @param  data   要输出数据的首地址
  * @param  len    要输出数据的内存大小
  * @retval 返回成功或者失败
  * @note   并不会顶出数据
  */
int8_t TSS_QueueBack(void *queue, void *data, uint16_t *len)
{
    if (MEM_NUM() == 0)
        return TSS_NODATA;
    memcpy((void *)data, (void *)MEM_DATAE(), MEM_LEN(MEM_NUM()));
    *len = MEM_LEN(MEM_NUM());
    return TSS_OK;
}

/**
  * @brief  顶出第一个数据
  * @param  queue  管理内存的首地址
  * @retval 返回成功或者失败
  * @note   无
  */
int8_t TSS_QueuePop(void *queue)
{
    if (MEM_NUM() == 0)
        return TSS_NODATA;
    memmove((void *)MEM_DATAF(), (void *)(MEM_DATAF() + MEM_LEN(1)), MEM_OCC() - MEM_LEN(1));
    MEM_OCC() -= MEM_LEN(1);
    memmove((void *)(&MEM_MOVE_8(queue, MEM_SIZE() - (MEM_NUM() - 1) * 2)),
            (void *)(&MEM_MOVE_8(queue, MEM_SIZE() - MEM_NUM() * 2)),
            (MEM_NUM() - 1) * 2);
    MEM_NUM() -= 1;
    return TSS_OK;
}

/**
  * @brief  判断是否队列为空
  * @param  queue  管理内存的首地址
  * @retval 返回是或否
  * @note   无
  */
int8_t TSS_QueueEmpty(void *queue)
{
    return !MEM_NUM();
}

/**
  * @brief  返回队列剩余字节数
  * @param  queue  管理内存的首地址
  * @retval 返回队列剩余字节数
  * @note   无
  */
int32_t TSS_QueueSpace(void *queue)
{
    return MEM_SPACE();
}
